home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / misc / gs261src.zip / gschar.c < prev    next >
C/C++ Source or Header  |  1993-05-27  |  25KB  |  787 lines

  1. /* Copyright (C) 1989, 1992, 1993 Aladdin Enterprises.  All rights reserved.
  2.  
  3. This file is part of Ghostscript.
  4.  
  5. Ghostscript is distributed in the hope that it will be useful, but
  6. WITHOUT ANY WARRANTY.  No author or distributor accepts responsibility
  7. to anyone for the consequences of using it or for whether it serves any
  8. particular purpose or works at all, unless he says so in writing.  Refer
  9. to the Ghostscript General Public License for full details.
  10.  
  11. Everyone is granted permission to copy, modify and redistribute
  12. Ghostscript, but only under the conditions described in the Ghostscript
  13. General Public License.  A copy of this license is supposed to have been
  14. given to you along with Ghostscript so you can know your rights and
  15. responsibilities.  It should be in a file named COPYING.  Among other
  16. things, the copyright notice and this notice must be preserved on all
  17. copies.  */
  18.  
  19. /* gschar.c */
  20. /* Character writing operators for Ghostscript library */
  21. #include "gx.h"
  22. #include "memory_.h"
  23. #include "string_.h"
  24. #include "gserrors.h"
  25. #include "gxfixed.h"            /* ditto */
  26. #include "gxarith.h"
  27. #include "gxmatrix.h"
  28. #include "gzstate.h"            /* must precede gzdevice */
  29. #include "gzdevice.h"            /* must precede gxchar */
  30. #include "gxdevmem.h"
  31. #include "gxchar.h"
  32. #include "gxcache.h"
  33. #include "gxfont.h"
  34. #include "gspath.h"
  35. #include "gzpath.h"
  36. #include "gzcolor.h"
  37.  
  38. /* Exported size of enumerator */
  39. const uint gs_show_enum_sizeof = sizeof(gs_show_enum);
  40.  
  41. /* Imported procedures */
  42. extern void gx_set_black(P1(gs_state *));
  43.  
  44. /* Forward declarations */
  45. private int continue_kshow(P1(gs_show_enum *));
  46. private int continue_show(P1(gs_show_enum *));
  47. private int continue_show_update(P1(gs_show_enum *));
  48. private int show_setup(P3(gs_show_enum *, gs_state *, const char *));
  49. private void show_cache_setup(P1(gs_show_enum *));
  50. private int show_state_setup(P1(gs_show_enum *));
  51. private int show_origin_setup(P4(gs_state *, fixed, fixed, int));
  52. private int stringwidth_setup(P3(gs_show_enum *, gs_state *, const char *));
  53.  
  54. /* Print the ctm if debugging */
  55. #define print_ctm(s,pgs)\
  56.   dprintf7("[p]%sctm=[%g %g %g %g %g %g]\n", s,\
  57.        pgs->ctm.xx, pgs->ctm.xy, pgs->ctm.yx, pgs->ctm.yy,\
  58.        pgs->ctm.tx, pgs->ctm.ty)
  59.  
  60. /* ------ String writing operators ------ */
  61.  
  62. /* Setup macros for show operators */
  63. #define setup_show_n()\
  64.   penum->size = size
  65. #define setup_a()\
  66.   penum->add = 1, penum->ax = ax, penum->ay = ay,\
  67.   penum->slow_show = 1
  68. #define setup_width()\
  69.   penum->wchr = chr, penum->wcx = cx, penum->wcy = cy,\
  70.   penum->slow_show = 1
  71.  
  72. /* show[_n] */
  73. int
  74. gs_show_n_init(register gs_show_enum *penum,
  75.    gs_state *pgs, const char *str, uint size)
  76. {    setup_show_n();
  77.     penum->slow_show = 0;
  78.     return show_setup(penum, pgs, str);
  79. }
  80. int
  81. gs_show_init(gs_show_enum *penum, gs_state *pgs, const char *str)
  82. {    return gs_show_n_init(penum, pgs, str, strlen(str));
  83. }
  84.  
  85. /* ashow[_n] */
  86. int
  87. gs_ashow_n_init(register gs_show_enum *penum,
  88.   gs_state *pgs, floatp ax, floatp ay, const char *str, uint size)
  89. {    int code;
  90.     setup_show_n();
  91.     code = show_setup(penum, pgs, str);
  92.     setup_a();
  93.     return code;
  94. }
  95. int
  96. gs_ashow_init(gs_show_enum *penum,
  97.   gs_state *pgs, floatp ax, floatp ay, const char *str)
  98. {    return gs_ashow_n_init(penum, pgs, ax, ay, str, strlen(str));
  99. }
  100.  
  101. /* widthshow[_n] */
  102. int
  103. gs_widthshow_n_init(register gs_show_enum *penum,
  104.   gs_state *pgs, floatp cx, floatp cy, gs_char chr, const char *str, uint size)
  105. {    int code;
  106.     setup_show_n();
  107.     code = show_setup(penum, pgs, str);
  108.     setup_width();
  109.     return code;
  110. }
  111. int
  112. gs_widthshow_init(gs_show_enum *penum,
  113.   gs_state *pgs, floatp cx, floatp cy, gs_char chr, const char *str)
  114. {    return gs_widthshow_n_init(penum, pgs, cx, cy, chr, str, strlen(str));
  115. }
  116.  
  117. /* awidthshow[_n] */
  118. int
  119. gs_awidthshow_n_init(register gs_show_enum *penum,
  120.   gs_state *pgs, floatp cx, floatp cy, gs_char chr, floatp ax, floatp ay,
  121.   const char *str, uint size)
  122. {    int code;
  123.     setup_show_n();
  124.     code = show_setup(penum, pgs, str);
  125.     setup_a();
  126.     setup_width();
  127.     return code;
  128. }
  129. int
  130. gs_awidthshow_init(gs_show_enum *penum,
  131.   gs_state *pgs, floatp cx, floatp cy, gs_char chr, floatp ax, floatp ay,
  132.   const char *str)
  133. {    return gs_awidthshow_n_init(penum, pgs, cx, cy, chr, ax, ay,
  134.                     str, strlen(str));
  135. }
  136.  
  137. /* kshow[_n] */
  138. int
  139. gs_kshow_n_init(register gs_show_enum *penum,
  140.   gs_state *pgs, const char *str, uint size)
  141. {    int code;
  142.     if ( pgs->font->FontType == ft_composite)
  143.         return_error(gs_error_invalidfont);
  144.     setup_show_n();
  145.     code = show_setup(penum, pgs, str);
  146.     penum->do_kern = penum->slow_show = 1;
  147.     return code;
  148. }
  149. int
  150. gs_kshow_init(gs_show_enum *penum, gs_state *pgs, const char *str)
  151. {    return gs_kshow_n_init(penum, pgs, str, strlen(str));
  152. }
  153.  
  154. /* xyshow[_n] */
  155. int
  156. gs_xyshow_n_init(register gs_show_enum *penum,
  157.    gs_state *pgs, const char *str, uint size)
  158. {    int code;
  159.     setup_show_n();
  160.     code = show_setup(penum, pgs, str);
  161.     penum->do_kern = -1;
  162.     penum->slow_show = 1;
  163.     return code;
  164. }
  165. int
  166. gs_xyshow_init(gs_show_enum *penum, gs_state *pgs, const char *str)
  167. {    return gs_xyshow_n_init(penum, pgs, str, strlen(str));
  168. }
  169.  
  170. /* glyphshow */
  171. private gs_proc_encode_char(gs_glyphshow_encode_char);
  172. int
  173. gs_glyphshow_init(gs_show_enum *penum, gs_state *pgs, gs_glyph glyph)
  174. {    int code;
  175.     if ( pgs->font->FontType == ft_composite)
  176.         return_error(gs_error_invalidfont);
  177.     penum->size = 1;
  178.     penum->slow_show = 0;
  179.     code = show_setup(penum, pgs, "\000");    /* arbitrary char */
  180.     penum->current_glyph = glyph;
  181.     penum->encode_char = gs_glyphshow_encode_char;
  182.     return code;
  183. }
  184. private gs_glyph
  185. gs_glyphshow_encode_char(gs_show_enum *penum, gs_font *pfont, gs_char *pchr)
  186. {    /* We just nil out the character, and return the pre-loaded glyph. */
  187.     *pchr = gs_no_char;
  188.     return penum->current_glyph;
  189. }
  190.  
  191. /* cshow[_n] */
  192. int
  193. gs_cshow_n_init(register gs_show_enum *penum,
  194.    gs_state *pgs, const char *str, uint size)
  195. {    int code;
  196.     setup_show_n();
  197.     code = show_setup(penum, pgs, str);
  198.     penum->do_kern = -1;
  199.     penum->stringwidth_flag = 1;
  200.     penum->slow_show = 1;
  201.     return code;
  202. }
  203. int
  204. gs_cshow_init(gs_show_enum *penum, gs_state *pgs, const char *str)
  205. {    return gs_cshow_n_init(penum, pgs, str, strlen(str));
  206. }
  207.  
  208. /* ------ Related operators ------ */
  209.  
  210. /* stringwidth[_n] */
  211. int
  212. gs_stringwidth_n_init(gs_show_enum *penum, gs_state *pgs, const char *str, uint size)
  213. {    setup_show_n();
  214.     return stringwidth_setup(penum, pgs, str);
  215. }
  216. int
  217. gs_stringwidth_init(gs_show_enum *penum, gs_state *pgs, const char *str)
  218. {    return gs_stringwidth_n_init(penum, pgs, str, strlen(str));
  219. }
  220.  
  221. /* Common code for stringwidth[_n] */
  222. private int
  223. stringwidth_setup(gs_show_enum *penum, gs_state *pgs, const char *str)
  224. {    int code = (penum->slow_show = 0, show_setup(penum, pgs, str));
  225.     if ( code < 0 ) return_error(code);
  226.     penum->stringwidth_flag = 1;
  227.     /* Do an extra gsave and suppress output */
  228.     if ( (code = gs_gsave(pgs)) < 0 ) return code;
  229.     penum->level = pgs->level;    /* for level check in show_update */
  230.     /* Set up a null device that forwards xfont requests properly. */
  231.     penum->dev_null = gs_null_device;
  232.     penum->dev_null.target = pgs->device->info;
  233.     pgs->device->info = (gx_device *)&penum->dev_null;
  234.     /* Establish an arbitrary current point. */
  235.     return gx_path_add_point(pgs->path, pgs->ctm.tx_fixed, pgs->ctm.ty_fixed);
  236. }
  237.  
  238. /* charpath[_n] */
  239. int
  240. gs_charpath_n_init(gs_show_enum *penum, gs_state *pgs,
  241.   const char *str, uint size, int bool)
  242. {    int code;
  243.     setup_show_n();
  244.     code = show_setup(penum, pgs, str);
  245.     penum->charpath_flag = (bool ? 2 : 1);
  246.     penum->can_cache = 0;
  247.     return code;
  248. }
  249. int
  250. gs_charpath_init(gs_show_enum *penum, gs_state *pgs,
  251.   const char *str, int bool)
  252. {    return gs_charpath_n_init(penum, pgs, str, strlen(str), bool);
  253. }
  254.  
  255. /* ------ Width/cache operators ------ */
  256.  
  257. private int set_cache_device(P6(gs_show_enum *, gs_state *,
  258.   floatp, floatp, floatp, floatp));
  259.  
  260. /* setcachedevice */
  261. int
  262. gs_setcachedevice(gs_show_enum *penum, gs_state *pgs,
  263.   floatp wx, floatp wy, floatp llx, floatp lly, floatp urx, floatp ury)
  264. {    int code = gs_setcharwidth(penum, pgs, wx, wy);    /* default is don't cache */
  265.     if ( code < 0 ) return code;
  266.     return set_cache_device(penum, pgs, llx, lly, urx, ury);
  267. }
  268.  
  269. /* setcachedevice2 */
  270. int
  271. gs_setcachedevice2(gs_show_enum *penum, gs_state *pgs,
  272.   floatp w0x, floatp w0y, floatp llx, floatp lly, floatp urx, floatp ury,
  273.   floatp w1x, floatp w1y, floatp vx, floatp vy)
  274. {    int code;
  275.     if ( penum->wmode )
  276.     {    code = gs_setcharwidth(penum, pgs, w1x, w1y);
  277.         if ( code < 0 ) return code;
  278.         /****** ADJUST ORIGIN BY vx, vy ******/
  279.     }
  280.     else
  281.     {    code = gs_setcharwidth(penum, pgs, w0x, w0y);
  282.         if ( code < 0 ) return code;
  283.     }
  284.     return set_cache_device(penum, pgs, llx, lly, urx, ury);
  285. }
  286.  
  287. /* Set up the cache device if relevant. */
  288. /* Used by setcachedevice and setcachedevice2. */
  289. private int
  290. set_cache_device(register gs_show_enum *penum, gs_state *pgs,
  291.   floatp llx, floatp lly, floatp urx, floatp ury)
  292. {    /* See if we want to cache this character. */
  293.     if ( pgs->in_cachedevice )        /* no recursion! */
  294.         return 0;
  295.     pgs->in_cachedevice = 1;    /* disable color/gray/image operators */
  296.     /* We can only use the cache if ctm is unchanged */
  297.     /* (aside from a possible translation), */
  298.     /* and if the extent of the box is non-negative. */
  299.     if ( !penum->can_cache || !pgs->char_tm_valid ||
  300.          llx > urx || lly > ury
  301.        )
  302.         return 0;
  303.        {    gs_font_dir *dir = pgs->font->dir;
  304.         gs_fixed_point cbox_ll, cbox_ur, cdim;
  305.         long iwidth, iheight;
  306.         cached_char *cc;
  307.         gs_fixed_rect clip_box;
  308.         int code;
  309.         gs_distance_transform2fixed(&pgs->ctm, llx, lly, &cbox_ll);
  310.         gs_distance_transform2fixed(&pgs->ctm, urx, ury, &cbox_ur);
  311.         cdim.x = cbox_ur.x - cbox_ll.x;
  312.         cdim.y = cbox_ur.y - cbox_ll.y;
  313.         if ( cdim.x < 0 ) cdim.x = -cdim.x;
  314.         if ( cdim.y < 0 ) cdim.y = -cdim.y;
  315. #ifdef DEBUG
  316. if ( gs_debug['k'] )
  317.    {    dprintf4("[k]cbox=[%g %g %g %g]\n",
  318.          fixed2float(cbox_ll.x), fixed2float(cbox_ll.y),
  319.          fixed2float(cbox_ur.x), fixed2float(cbox_ur.y));
  320.     print_ctm("  ", pgs);
  321.    }
  322. #endif
  323.         iwidth = fixed2long(cdim.x) + 2;
  324.         iheight = fixed2long(cdim.y) + 2;
  325.         if (    iwidth != (ushort)iwidth ||
  326.             iheight != (ushort)iheight
  327.            )
  328.           return 0;        /* much too big */
  329.         if ( !penum->cache_set )
  330.             show_cache_setup(penum);
  331.         cc = gx_alloc_char_bits(dir,
  332.                 (gx_device_memory *)&penum->dev_cache_info,
  333.                 (ushort)iwidth,
  334.                 (ushort)iheight);
  335.         if ( cc == 0 )
  336.             return 0;    /* too big for cache */
  337.         /* The mins handle transposed coordinate systems.... */
  338.         /* Truncate the offsets to avoid artifacts later. */
  339.         cc->offset.x = fixed_ceiling(-min(cbox_ll.x, cbox_ur.x));
  340.         cc->offset.y = fixed_ceiling(-min(cbox_ll.y, cbox_ur.y));
  341.         if_debug4('k', "[k]width=%ld, height=%ld, offset=[%g %g]\n",
  342.               iwidth, iheight,
  343.               fixed2float(cc->offset.x),
  344.               fixed2float(cc->offset.y));
  345.         if ( (code = gs_gsave(pgs)) < 0 )
  346.            {    gx_free_cached_char(dir, cc);
  347.             return code;
  348.            }
  349.         /* Nothing can go wrong now.... */
  350.         penum->cc = cc;
  351.         cc->code = gs_show_current_glyph(penum);
  352.         cc->wmode = penum->wmode;
  353.         cc->wxy = penum->wxy;
  354.         /* Install the device */
  355.         pgs->device = &penum->dev_cache_dev;
  356.         pgs->device_is_shared = 1;    /* don't deallocate */
  357.         /* Adjust the translation in the graphics context */
  358.         /* so that the character lines up with the cache. */
  359.         gs_translate_to_fixed(pgs, cc->offset.x, cc->offset.y);
  360.         /* Set the initial matrix for the cache device. */
  361.         penum->dev_cache_info.initial_matrix = ctm_only(pgs);
  362.         /* Reset the clipping path to match the metrics. */
  363.         clip_box.p.x = clip_box.p.y = 0;
  364.         clip_box.q.x = int2fixed(iwidth);
  365.         clip_box.q.y = int2fixed(iheight);
  366.         if ( (code = gx_clip_to_rectangle(pgs, &clip_box)) < 0 )
  367.           return code;
  368.         gx_set_black(pgs);    /* Set the color to black. */
  369.        }
  370.     penum->width_status = sws_cache;
  371.     return 0;
  372. }
  373.  
  374. /* setcharwidth */
  375. int
  376. gs_setcharwidth(register gs_show_enum *penum, gs_state *pgs, floatp wx, floatp wy)
  377. {    if ( penum->width_status != sws_none )
  378.         return_error(gs_error_undefined);
  379.     gs_distance_transform2fixed(&pgs->ctm, wx, wy, &penum->wxy);
  380.     penum->width_status = sws_no_cache;
  381.     return 0;
  382. }
  383.  
  384. /* ------ Enumerator ------ */
  385.  
  386. /* Do the next step of a show (or stringwidth) operation */
  387. int
  388. gs_show_next(gs_show_enum *penum)
  389. {    return (*penum->continue_proc)(penum);
  390. }
  391.  
  392. /* Continuation procedures */
  393. #define show_fast_move(wxy, pgs)\
  394.   gx_path_add_rel_point_inline(pgs->path, wxy.x, wxy.y)
  395. private int show_update(P1(gs_show_enum *penum));
  396. private int show_move(P1(gs_show_enum *penum));
  397. private int show_proceed(P1(gs_show_enum *penum));
  398. private int show_finish(P1(gs_show_enum *penum));
  399. private int
  400. continue_show_update(register gs_show_enum *penum)
  401. {    int code = show_update(penum);
  402.     if ( code < 0 ) return code;
  403.     code = show_move(penum);
  404.     if ( code != 0 ) return code;
  405.     return show_proceed(penum);
  406. }
  407. private int
  408. continue_show(register gs_show_enum *penum)
  409. {    return show_proceed(penum);
  410. }
  411. /* For kshow, the CTM or font may have changed, so we have to reestablish */
  412. /* the cached values in the enumerator. */
  413. private int
  414. continue_kshow(register gs_show_enum *penum)
  415. {    int code = show_state_setup(penum);
  416.     if ( code < 0 ) return code;
  417.     return show_proceed(penum);
  418. }
  419.  
  420. /* Update position */
  421. private int
  422. show_update(register gs_show_enum *penum)
  423. {    register gs_state *pgs = penum->pgs;
  424.     /* Update position for last character */
  425.     switch ( penum->width_status )
  426.        {
  427.     case sws_none:
  428.         /* Adobe interpreters assume a character width of 0, */
  429.         /* even though the documentation says this is an error.... */
  430.         penum->wxy.x = penum->wxy.y = 0;
  431.         break;
  432.     case sws_cache:
  433.        {    /* Finish installing the cache entry. */
  434.         cached_char *cc = penum->cc;
  435.         int code;
  436.         /* If the BuildChar/BuildGlyph procedure did a save and a */
  437.         /* restore, it already undid the gsave in setcachedevice. */
  438.         /* We have to check for this by comparing levels. */
  439.         switch ( pgs->level - penum->level )
  440.            {
  441.         default:
  442.             return_error(gs_error_invalidfont);    /* WRONG */
  443.         case 2:
  444.             code = gs_grestore(pgs);
  445.             if ( code < 0 ) return code;
  446.         case 1:
  447.             ;
  448.            }
  449.         gx_add_cached_char(pgs->font->dir, &penum->dev_cache_info,
  450.                    cc, gx_lookup_fm_pair(pgs),
  451.                    penum->current_scale);
  452.         if ( !penum->stringwidth_flag && !penum->charpath_flag )
  453.         {    /* Copy the bits to the real output device. */
  454.             code = gs_grestore(pgs);
  455.             if ( code < 0 ) return code;
  456.             code = gx_color_load(pgs->dev_color, pgs);
  457.             if ( code < 0 ) return code;
  458.             return gx_image_cached_char(penum, cc);
  459.         }
  460.        }
  461.     case sws_no_cache: ;
  462.        }
  463.     if ( penum->charpath_flag )
  464.     {    /* Move back to the character origin, so that */
  465.         /* show_move will get us to the right place. */
  466.         int code = gx_path_add_point(pgs->show_gstate->path,
  467.                 penum->origin.x, penum->origin.y);
  468.         if ( code < 0 ) return code;
  469.     }
  470.     return gs_grestore(pgs);
  471. }
  472.  
  473. /* Move to next character */
  474. private int
  475. show_move(register gs_show_enum *penum)
  476. {    register gs_state *pgs = penum->pgs;
  477.     if ( penum->do_kern < 0 )
  478.     {    /* xyshow or cshow */
  479.         /****** WRONG FOR cshow, MUST MOVE FIRST ******/
  480.         penum->continue_proc = continue_show;
  481.         return gs_show_move;
  482.     }
  483.     if ( penum->add )
  484.         gs_rmoveto(pgs, penum->ax, penum->ay);
  485.     if ( penum->str[penum->index - 1] == penum->wchr )
  486.         gs_rmoveto(pgs, penum->wcx, penum->wcy);
  487.     /* wxy is in device coordinates */
  488.        {    int code = show_fast_move(penum->wxy, pgs);
  489.         if ( code < 0 ) return code;
  490.        }
  491.     /* Check for kerning, but not on the last character. */
  492.     if ( penum->do_kern && penum->index < penum->size )
  493.        {    penum->continue_proc = continue_kshow;
  494.         return gs_show_kern;
  495.        }
  496.     return 0;
  497. }
  498. /* Process next character */
  499. private int
  500. show_proceed(register gs_show_enum *penum)
  501. {    register gs_state *pgs = penum->pgs;
  502.     const byte *str = penum->str;
  503.     uint index;
  504.     gs_font *pfont;
  505.     cached_fm_pair *pair = 0;
  506.     int wmode = penum->wmode;
  507.     gs_char chr;
  508.     gs_glyph glyph;
  509.     int code;
  510.     code = gx_color_load(pgs->dev_color, pgs);
  511.     if ( code < 0 ) return code;
  512. more:    /* Proceed to next character */
  513.     pfont = pgs->font;
  514.     if ( penum->can_cache )
  515.        {    /* Loop with cache */
  516.         if ( pair == 0 )
  517.           pair = gx_lookup_fm_pair(pgs);
  518.         while ( (index = penum->index++) != penum->size )
  519.         {    cached_char *cc;
  520.             chr = str[index];
  521.             glyph = (*penum->encode_char)(penum, pfont, &chr);
  522.             if ( glyph == gs_no_glyph )
  523.                 goto no_cache;
  524.             cc = gx_lookup_cached_char(pgs, pair, glyph, wmode);
  525.             if ( cc == 0 )
  526.             {    /* If possible, try for an xfont before */
  527.                 /* rendering from the outline. */
  528.                 if ( pfont->ExactSize == fbit_use_outlines )
  529.                     goto no_cache;
  530.                 cc = gx_lookup_xfont_char(pgs, pair, chr,
  531.                     glyph, pfont->glyph_name_proc, wmode);
  532.                 if ( cc == 0 )
  533.                     goto no_cache;
  534.             }
  535.             /* Character is in cache. */
  536.             if ( !penum->stringwidth_flag )
  537.             {    code = gx_image_cached_char(penum, cc);
  538.                 if ( code < 0 ) return code;
  539.                 else if ( code > 0 ) goto no_cache;
  540.             }
  541.             if ( penum->slow_show )
  542.             {    /* Split up the assignment so that the */
  543.                 /* Watcom compiler won't reserve esi/edi. */
  544.                 penum->wxy.x = cc->wxy.x;
  545.                 penum->wxy.y = cc->wxy.y;
  546.                 code = show_move(penum);
  547.             }
  548.             else
  549.                 code = show_fast_move(cc->wxy, pgs);
  550.             if ( code ) return code;
  551.         }
  552.         /* All done. */
  553.         return show_finish(penum);
  554.        }
  555.     else
  556.        {    /* Can't use cache */
  557.         if ( (index = penum->index++) == penum->size )
  558.           {    /* All done. */
  559.             return show_finish(penum);
  560.           }
  561.         chr = str[index];
  562.         glyph = (*penum->encode_char)(penum, pfont, &chr);
  563.        }
  564. no_cache:
  565.     /* Character is not cached, client must render it. */
  566.     penum->current_char = chr;
  567.     penum->current_glyph = glyph;
  568.     if ( (code = gs_gsave(pgs)) < 0 )
  569.         return code;
  570.     /* Reset the in_cachedevice flag, so that a recursive show */
  571.     /* will use the cache properly. */
  572.     pgs->in_cachedevice = 0;
  573.     /* Reset the sampling scale, which is only used by Type 1 outlines. */
  574.     penum->current_scale = 1;
  575.     /* Set the charpath flag in the graphics context if necessary, */
  576.     /* so that fill and stroke will add to the path */
  577.     /* rather than having their usual effect. */
  578.     pgs->in_charpath = penum->charpath_flag;
  579.     pgs->stroke_adjust = 0;        /* per specification */
  580.        {    gs_fixed_point cpt;
  581.         gx_path *ppath = pgs->path;
  582.         if ( (code = gx_path_current_point_inline(ppath, &cpt)) < 0 )
  583.             return code;
  584.         cpt.x -= pgs->ctm.tx_fixed;
  585.         cpt.y -= pgs->ctm.ty_fixed;
  586.         gs_setmatrix(pgs, &char_tm_only(pgs));
  587.         penum->origin.x = cpt.x += pgs->ctm.tx_fixed;
  588.         penum->origin.y = cpt.y += pgs->ctm.ty_fixed;
  589.         gs_newpath(pgs);
  590.         code = show_origin_setup(pgs, cpt.x, cpt.y,
  591.                      penum->charpath_flag);
  592.         if ( code < 0 ) return code;
  593.        }
  594.     penum->width_status = sws_none;
  595.     penum->continue_proc = continue_show_update;
  596.     /* Try using the build procedure in the font. */
  597.     /* < 0 means error, 0 means success, 1 means failure. */
  598.     code = (*pfont->build_char_proc)(penum, pgs, pfont, chr, glyph);
  599.     if ( code < 0 ) return_error(code);
  600.     if ( code == 0 )
  601.        {    code = show_update(penum);
  602.         if ( code < 0 ) return code;
  603.         code = show_move(penum);
  604.         if ( code ) return code;
  605.         goto more;
  606.        }
  607.     return gs_show_render;
  608. }
  609.  
  610. /* Finish show or stringwidth */
  611. private int
  612. show_finish(register gs_show_enum *penum)
  613. {    register gs_state *pgs = penum->pgs;
  614.     int code;
  615.     if ( !penum->stringwidth_flag ) return 0;
  616.     /* Save the accumulated width before returning, */
  617.     /* and undo the extra gsave. */
  618.     code = gs_currentpoint(pgs, &penum->width);
  619.     if ( code < 0 ) return code;
  620.     return gs_grestore(pgs);
  621. }
  622.  
  623. /* Return the current character for rendering. */
  624. gs_char
  625. gs_show_current_char(const gs_show_enum *penum)
  626. {    return penum->current_char;
  627. }
  628.  
  629. /* Return the current glyph for rendering. */
  630. gs_glyph
  631. gs_show_current_glyph(const gs_show_enum *penum)
  632. {    return penum->current_glyph;
  633. }
  634.  
  635. /* Return the width of the just-enumerated character (for cshow). */
  636. int
  637. gs_show_current_width(const gs_show_enum *penum, gs_point *ppt)
  638. {    return gs_idtransform(penum->pgs, fixed2float(penum->wxy.x),
  639.                   fixed2float(penum->wxy.y), ppt);
  640. }
  641.  
  642. /* Return the just-displayed character for kerning. */
  643. gs_char
  644. gs_kshow_previous_char(const gs_show_enum *penum)
  645. {    return penum->current_char;
  646. }
  647.  
  648. /* Return the about-to-be-displayed character for kerning. */
  649. gs_char
  650. gs_kshow_next_char(const gs_show_enum *penum)
  651. {    return penum->str[penum->index];
  652. }
  653.  
  654. /* ------ Miscellaneous accessors ------ */
  655.  
  656. /* Return the root font of the current font. */
  657. gs_font *
  658. gs_rootfont(gs_show_enum *penum, gs_state *pgs)
  659. {    return (penum == 0 || penum->fdepth < 0 ? gs_currentfont(pgs) : penum->fstack[0]);
  660. }
  661.  
  662. /* Return the accumulated width for stringwidth. */
  663. void
  664. gs_show_width(const gs_show_enum *penum, gs_point *ppt)
  665. {    *ppt = penum->width;
  666. }
  667.  
  668. /* Return the charpath flag. */
  669. int
  670. gs_show_in_charpath(const gs_show_enum *penum)
  671. {    return penum->charpath_flag;
  672. }
  673.  
  674. /* ------ Internal routines ------ */
  675.  
  676. /* Initialize a show enumerator. */
  677. private int
  678. show_setup(register gs_show_enum *penum, gs_state *pgs, const char *str)
  679. {    int code;
  680.     gs_font *pfont = pgs->font;
  681.     penum->pgs = pgs;
  682.     penum->level = pgs->level;
  683.     penum->str = (const byte *)str;    /* avoid signed chars */
  684.     penum->wchr = gs_no_char;
  685.     penum->add = 0;
  686.     penum->do_kern = 0;
  687.     penum->charpath_flag = 0;
  688.     penum->stringwidth_flag = 0;
  689.     penum->index = 0;
  690.     penum->continue_proc = continue_show;
  691.     if ( (penum->is_composite = pfont->FontType == ft_composite) )
  692.        {    gs_font *rfont = pgs->font;
  693.         penum->fstack[0] = rfont;
  694.         penum->fdepth = 0;
  695.         penum->pfont =
  696.           rfont->data.type0_data.FDepVector[rfont->data.type0_data.Encoding[0]];
  697.        }
  698.     else
  699.         penum->fdepth = -1;
  700.     penum->wmode = pfont->WMode;
  701.     penum->can_cache = 1;        /* show_state_setup may reset */
  702.     code = show_state_setup(penum);
  703.     if ( code < 0 ) return code;
  704.     penum->cache_set = 0;
  705.     pgs->show_gstate = pgs;
  706.     return 0;
  707. }
  708.  
  709. /* Initialize the gstate-derived parts of a show enumerator. */
  710. /* We do this both when starting the show operation, */
  711. /* and when returning from the kshow callout. */
  712. private int
  713. show_state_setup(gs_show_enum *penum)
  714. {    gs_state *pgs = penum->pgs;
  715.     gs_currentcharmatrix(pgs, NULL, 1);    /* make char_tm valid */
  716.     if ( penum->can_cache &= /* no skewing or non-rectangular rotation */
  717.         (is_fzero2(pgs->char_tm.xy, pgs->char_tm.yx) ||
  718.          is_fzero2(pgs->char_tm.xx, pgs->char_tm.yy)) )
  719.        {    gs_fixed_rect cbox;
  720.         gx_cpath_box_for_check(pgs->clip_path, &cbox);
  721.         penum->ibox.p.x = fixed2int_var_ceiling(cbox.p.x);
  722.         penum->ibox.p.y = fixed2int_var_ceiling(cbox.p.y);
  723.         penum->ibox.q.x = fixed2int_var(cbox.q.x);
  724.         penum->ibox.q.y = fixed2int_var(cbox.q.y);
  725.         gx_path_bbox(&pgs->clip_path->path, &cbox);
  726.         penum->obox.p.x = fixed2int_var(cbox.p.x);
  727.         penum->obox.p.y = fixed2int_var(cbox.p.y);
  728.         penum->obox.q.x = fixed2int_var_ceiling(cbox.q.x);
  729.         penum->obox.q.y = fixed2int_var_ceiling(cbox.q.y);
  730.         penum->ftx = (int)fixed2long(pgs->char_tm.tx_fixed - pgs->ctm.tx_fixed);
  731.         penum->fty = (int)fixed2long(pgs->char_tm.ty_fixed - pgs->ctm.ty_fixed);
  732.        }
  733.     penum->encode_char = pgs->font->encode_char_proc;
  734.     return 0;
  735. }
  736.  
  737. /* Set up the cache device and related information. */
  738. private void
  739. show_cache_setup(gs_show_enum *penum)
  740. {    gs_state *pgs = penum->pgs;
  741.     device *dev = &penum->dev_cache_dev;
  742.     penum->dev_cache_info = mem_mono_device;
  743.     penum->dev_cache_info.target = pgs->device->info;
  744.     dev->info = (gx_device *)&penum->dev_cache_info;
  745.     dev->is_band_device = 0;
  746.     dev->white = 1;
  747.     dev->black = 1;
  748.     /* Decide whether to oversample. */
  749.     /* We have to decide this now, because */
  750.     /* type1addpath has to know it in advance. */
  751.     if ( penum->is_composite )
  752.     {    penum->suggested_scale = 1;    /* WRONG, should */
  753.                 /* use info from eventual base font */
  754.     }
  755.     else
  756.     {    gs_font *pfont = pgs->font;
  757.         gs_fixed_point extent;
  758.         gs_distance_transform2fixed(&pgs->char_tm,
  759.             pfont->data.base.FontBBox.q.x -
  760.               pfont->data.base.FontBBox.p.x,
  761.             pfont->data.base.FontBBox.q.y -
  762.               pfont->data.base.FontBBox.p.y,
  763.             &extent);
  764.         penum->suggested_scale =
  765.           (extent.x != 0 && extent.y != 0 &&
  766.            any_abs(extent.x) < int2fixed(16) &&
  767.            any_abs(extent.y) < int2fixed(16) ? 4 : 1);
  768.     }
  769.     penum->cache_set = 1;
  770. }
  771.  
  772. /* Set the character origin as the origin of the coordinate system. */
  773. /* Used before rendering characters, and for moving the origin */
  774. /* in setcachedevice2 when WMode=1. */
  775. private int
  776. show_origin_setup(gs_state *pgs, fixed cpt_x, fixed cpt_y, int charpath_flag)
  777. {    if ( !charpath_flag )
  778.       { /* Round the translation in the graphics state. */
  779.         /* This helps prevent rounding artifacts later. */
  780.         cpt_x = fixed_rounded(cpt_x);
  781.         cpt_y = fixed_rounded(cpt_y);
  782.       }
  783.     gs_translate_to_fixed(pgs, cpt_x, cpt_y);
  784.     return gx_path_add_point(pgs->path, pgs->ctm.tx_fixed,
  785.                  pgs->ctm.ty_fixed);
  786. }
  787.